package com.andova.net;

import android.app.Dialog;
import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.andova.NETWORK;
import com.andova.component.AndovaComponentManager;
import com.andova.component.net.AndovaNetCallback2;
import com.andova.component.net.ResponseModel;
import com.google.gson.JsonSyntaxException;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;

import okhttp3.MediaType;
import okhttp3.Request;
import okio.Buffer;
import retrofit2.Call;
import retrofit2.Response;

import static com.andova.CodeExtKt.ERROR_NO_NETWORK;

/**
 * Created by Administrator on 2019-02-12.
 *
 * @author kzaxil
 * @since 0.0.4
 */
public abstract class NetCallback2<T extends ResponseModel> implements AndovaNetCallback2<T> {
    private int mPage = 1;
    public static final String TAG_NETWORK = "TAG_NETWORK";

    public void call(@NonNull WeakReference<Context> context, Call<T> call) {
        AndovaComponentManager.getInstance().netComponent().netCall2().request(context, this, call);
    }

    @Override
    public final void prepare(@NonNull WeakReference<Context> weakReference) {
        if (!showDialog() || mPage != 1) return;
        if (dialog() != null) dialog().show();
    }

    @Override
    public final void error(@NonNull WeakReference<Context> weakReference, Object obj) {
        if (weakReference.get() == null || !(obj instanceof Response)) return;
        print_response(true, ((Response) obj).raw());
    }

    @Override
    public final void success(@NonNull WeakReference<Context> weakReference, T respBody) {
        mPage++;
        func().handle(respBody);
    }

    @Override
    public final void response(@NonNull WeakReference<Context> weakReference, Object... objects) {
        try {
            if (dialog() != null) dialog().dismiss();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        for (Object obj : objects) {
            if (!(obj instanceof Response)) continue;
            Response response = (Response) obj;
            print_request(false, response.raw().request());
        }
    }

    @Override
    public final void failure(@NonNull WeakReference<Context> weakReference, Throwable throwable, Object... objects) {
        try {
            if (dialog() != null) dialog().dismiss();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        for (Object obj : objects) {
            if (!(obj instanceof Call)) continue;
            Call response = (Call) obj;
            print_request(true, response.request());
        }
        if (throwable instanceof JsonSyntaxException) {
            Log.e(TAG_NETWORK, "数据解析出错");
        } else if (throwable instanceof SocketTimeoutException) {
            Log.e(TAG_NETWORK, "连接超时");
        } else if (throwable instanceof ConnectException) {
            Log.e(TAG_NETWORK, "连接服务器异常");
        } else {
            Log.e(TAG_NETWORK, "获取网络数据失败");
        }
    }

    @Override
    public final void complete(@NonNull WeakReference<Context> weakReference, @NETWORK int code) {
        if (code == ERROR_NO_NETWORK) {
            Log.e(TAG_NETWORK, "无可用网络");
            return;
        }
        func().complete(code);
    }

    @SuppressWarnings("WeakerAccess")
    protected boolean showDialog() {
        return false;
    }

    @SuppressWarnings("WeakerAccess")
    protected Dialog dialog() {
        return null;
    }

    public void reset() {
        mPage = 1;
    }

    public int page() {
        return mPage;
    }

    private void print_request(boolean error, Request request) {
        try {
            Buffer buffer = new Buffer();
            request.body().writeTo(buffer);

            Charset charset = Charset.forName("UTF-8");
            MediaType contentType = request.body().contentType();
            if (contentType != null) {
                charset = contentType.charset(Charset.forName("UTF-8"));
            }
            if (error) {
                Log.e(TAG_NETWORK, request.toString() + "\nthe request body is:" + buffer.readString(charset));
            } else {
                Log.i(TAG_NETWORK, request.toString() + "\nthe request body is:" + buffer.readString(charset));
            }
        } catch (IOException | NullPointerException e) {
            if (error) {
                Log.e(TAG_NETWORK, "the request body is:" + request.toString());
            } else {
                Log.i(TAG_NETWORK, "the request body is:" + request.toString());
            }
        }
    }

    private void print_response(boolean error, okhttp3.Response response) {
        if (error) {
            Log.e(TAG_NETWORK, response.toString());
        } else {
            Log.i(TAG_NETWORK, response.toString());
        }
    }

    @NonNull
    protected abstract NetworkHandleFunc2<T> func();
}
